package com.amigo.online.provider.video.service.impl;

import java.util.*;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONObject;
import com.amigo.online.common.base.security.LocalUser;
import com.amigo.online.common.base.service.BaseService;
import com.amigo.online.common.core.response.Response;
import com.amigo.online.common.core.response.StatusCode;
import com.amigo.online.common.param.RedisKey;
import com.amigo.online.common.param.common.MqTag;
import com.amigo.online.common.param.dto.video.LookVideoDto;
import com.amigo.online.common.param.dto.video.ShareVideoDto;
import com.amigo.online.common.param.dto.video.VideoCommentQueryDto;
import com.amigo.online.common.param.dto.video.VideoDto;
import com.amigo.online.common.param.dto.video.VideoQueryDto;
import com.amigo.online.common.param.result.AroundVideoInfo;
import com.amigo.online.common.param.result.LocalUserInfo;
import com.amigo.online.common.param.result.MusicInfo;
import com.amigo.online.common.param.result.UserInfo;
import com.amigo.online.common.param.result.UserPointInfo;
import com.amigo.online.common.param.result.VideoInfo;
import com.amigo.online.common.param.result.VideoInfo.VideoUserInfo;
import com.amigo.online.common.param.result.VideoWhoSawMeInfo;
import com.amigo.online.common.param.result.VideoWithWaterMarkInfo;
import com.amigo.online.common.param.result.WaterMarkVideoInfo;
import com.amigo.online.common.util.DistanceHandleUtil;
import com.amigo.online.common.util.StringUtils;
import com.amigo.online.provider.video.common.ConstantValue;
import com.amigo.online.provider.video.common.GlobalController;
import com.amigo.online.provider.video.common.RwRedisService;
import com.amigo.online.provider.video.exception.MusicException;
import com.amigo.online.provider.video.exception.VideoException;
import com.amigo.online.provider.video.mapper.MusicMapper;
import com.amigo.online.provider.video.mapper.PromoteMapper;
import com.amigo.online.provider.video.mapper.UserBalanceMapper;
import com.amigo.online.provider.video.mapper.VideoCollectMapper;
import com.amigo.online.provider.video.mapper.VideoCommentMapper;
import com.amigo.online.provider.video.mapper.VideoLookMapper;
import com.amigo.online.provider.video.mapper.VideoMapper;
import com.amigo.online.provider.video.mapper.VideoRecommendMapper;
import com.amigo.online.provider.video.mapper.VideoUpMapper;
import com.amigo.online.provider.video.model.entity.Music;
import com.amigo.online.provider.video.model.entity.PromoteVideo;
import com.amigo.online.provider.video.model.entity.Video;
import com.amigo.online.provider.video.model.entity.VideoCollect;
import com.amigo.online.provider.video.model.entity.VideoComment;
import com.amigo.online.provider.video.model.entity.VideoLook;
import com.amigo.online.provider.video.model.entity.VideoRecomend;
import com.amigo.online.provider.video.model.entity.VideoUp;
import com.amigo.online.provider.video.mongo.dao.VideoDao;
import com.amigo.online.provider.video.rocketmq.RocketMqUtil;
import com.amigo.online.provider.video.service.UserFeignService;
import com.amigo.online.provider.video.service.VideoService;
import com.amigo.online.provider.video.util.ConvertUtil;
import com.amigo.online.provider.video.util.LocationUtils;
import com.amigo.online.provider.video.util.PricePerViewUtil;
import com.amigo.online.provider.video.util.TodayZeroPointTimeStampsUtil;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mongodb.BasicDBObject;
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.MongoCursor;

import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.entity.Example.Criteria;

@Service
@Transactional(rollbackFor = Exception.class)
@SuppressWarnings({"unchecked", "rawtypes"})
public class VideoServiceImpl extends BaseService<Video> implements VideoService {
    @Resource
    private VideoMapper videoMapper;

    @Resource
    private VideoLookMapper videoLookMapper;

    @Resource
    private VideoUpMapper videoUpMapper;

    @Resource
    private VideoCommentMapper videoCommentMapper;

    @Resource
    private VideoCollectMapper videoCollectMapper;

    @Resource
    private VideoDao videoDao;

    @Resource
    private VideoRecommendMapper videoRecommendMapper;

    @Resource
    UserFeignService userFeignService;

    @Autowired
    RwRedisService rwRedisService;

    @Resource
    private MusicMapper musicMapper;

    @Autowired
    PromoteMapper promoteMapper;

    @Autowired
    UserBalanceMapper userBalanceMapper;

    // private Logger logger = LoggerFactory.getLogger(VideoServiceImpl.class);

    private static String video_comment_key = RedisKey.VIDEO_COMMENT_KEY;
    private static String video_comment_id_key = RedisKey.VIDEO_COMMENT_ID_KEY;
    private static String video_reids_key = RedisKey.VIDEO_REDIS_KEY;
    private final static int VIDEO_COUNT_ONE_PAGE = 10;

    private final static String LOOKED_VIDEO_ID_KEY_PREFIX = "v:mvi:";
    private final static String LOOKED_PROMOTE_VIDEO_ID_KEY_PREFIX = "v:mpvi:";
    private final static String DAILY_COST_KEY_PREFIX = "m:dailycost:";

    @Override
    public VideoInfo newUserVideo(VideoDto dto) {
        UserInfo userInfo = GlobalController.getNowUser();
        Video video = new Video();
        video.setUserId(userInfo.getId());
        video.setVideo(dto.getVideo());
        video.setCover(dto.getCover());
        video.setDuration(dto.getDuration());
        video.setTitle(dto.getTitle());
        video.setContent(dto.getContent());
        video.setDestroy(dto.getDestroy());
        video.setLongitude(dto.getLongitude());
        video.setLatitude(dto.getLatitude());
        video.setWidth(dto.getWidth());
        video.setHeight(dto.getHeight());
        long nowSeconds = System.currentTimeMillis() / 1000;
        video.setCreatedTime(nowSeconds);
        video.setUpdatedTime(nowSeconds);
        video.setDeleted(0);
        video.setDeletedTime(0L);
        video.setAreaId(dto.getAreaId());
        video.setMusicId(StringUtils.isNotBlank(dto.getMusicId()) ? Long.valueOf(dto.getMusicId()) : null);
        video.setShare(0);
        video.setUp(0);
        video.setComment(0);
        if(userInfo.getType()!=null && userInfo.getType()==3){
            video.setType(userInfo.getType());
        }
        if (videoMapper.insertSelective(video) <= 0) {
            throw new VideoException(StatusCode.NEW_VIDEO_FAILED);
        }
        VideoInfo videoInfo = ConvertUtil.videoToVideoInfo(video);
		/*
		 * 异步处理
		VideoEntity ve = new VideoEntity();
		ve.setId(video.getId());
		ve.setUserId(video.getUserId());
		ve.setType(0);
		ve.setRecommended(0);
		ve.setCover(video.getCover());
		ve.setCreatedTime(video.getCreatedTime());
		ve.setNickname(userInfo.getNickname());
		ve.setAvatar(userInfo.getAvatar());
		ve.setAreaId(video.getAreaId());
		Double[] point = new Double[2];
		point[0] = Double.parseDouble(video.getLongitude());
		point[1] = Double.parseDouble(video.getLatitude());
		Loc loc = new Loc();
		loc.setType("Point");
		loc.setCoordinates(point);
		ve.setLoc(loc);
		videoInfo.setAvatar(userInfo.getAvatar());
		videoInfo.setNickname(userInfo.getNickname());
		videoInfo.setAccount(userInfo.getAccount());
		videoDao.saveVideo(ve);*/

        // 视频加水印消息
        if (dto.getAccount() != null) {
            Map<String, Object> videoMap = new HashMap<>();
            videoMap.put("video", video.getVideo());
            videoMap.put("title", video.getTitle());
            videoMap.put("width", video.getWidth());
            videoMap.put("account", dto.getAccount());
            videoMap.put("id", video.getId());
            videoMap.put("userId", video.getUserId());
            if (video.getMusicId() != null) {
                videoMap.put("musicId", video.getMusicId());
            }
            RocketMqUtil.send(MqTag.ROCKETMQ_BEAN_VIDEOADDWATERMARK, videoMap, MqTag.FFMPEG);
        } else {
            logger.error("---------------老版接口未做兼容。运维去手动处理-----------");
        }

        rwRedisService.hput(RedisKey.VIDEO_REDIS_KEY, videoInfo.getId(), videoInfo);
        rwRedisService.leftPush(RedisKey.VIDEO_REDIS_ID_KEY, videoInfo.getId());
        return videoInfo;
    }

    @Override
    public VideoInfo getVideoInfoById(Long id) {
//        VideoInfo videoInfo = (VideoInfo) rwRedisService.hget(video_reids_key, id);

//        if (videoInfo == null) {
        VideoInfo videoInfo = videoMapper.getVideoInfoByvideoId(id);
            if (videoInfo == null) {
                throw new VideoException(StatusCode.BAD_REQUEST);
            } else {
                rwRedisService.hput(RedisKey.VIDEO_REDIS_KEY, id, videoInfo);
            }
//        }
        ResponseEntity<Response> res = userFeignService.getVideoUserInfoById(videoInfo.getUserId());
        if (res.getStatusCodeValue() != 200) {
            throw new VideoException(StatusCode.USER_EXCEPTION);
        }
        if (res.getBody() == null) {
            throw new VideoException(StatusCode.USER_EXCEPTION);
        }
        if (res.getBody().getMeta().getCode() != 200) {
            throw new VideoException(StatusCode.USER_EXCEPTION);
        }
        Object videoUserInfo = res.getBody().getData();
        if (videoUserInfo == null) {
            throw new VideoException(StatusCode.USER_EXCEPTION);
        }
        ObjectMapper objectMapper = new ObjectMapper();
        VideoUserInfo user = objectMapper.convertValue(videoUserInfo, VideoUserInfo.class);
        user.setAccount(user.getAccount());
        user.setAvatar(user.getAvatar());
        videoInfo.setUser(user);
        return videoInfo;
    }

    @Override
    public boolean lookVideoById(long id, long lookTime) {
        UserInfo u = GlobalController.getNowUser();
        Video lookvideo = videoMapper.selectByPrimaryKey(id);
        if (lookvideo == null) {
            throw new VideoException(StatusCode.BAD_REQUEST);
        }
        long nowSeconds = System.currentTimeMillis() / 1000;
        VideoLook vl = new VideoLook();
        vl.setVideoId(id);
        vl.setUserId(u.getId());
        vl.setLookTime(lookTime);
        vl.setCreatedTime(nowSeconds);
        // videolook表有则更新，无则插入（解决并发多条插入问题）
        if (videoLookMapper.insertIfNotExited(vl) > 0) { // 插入成功则说明这个video没有观看
            // video表的look+1
            if (videoMapper.updateLook(id) <= 0) {
                throw new VideoException(StatusCode.VIDEO_EXCEPTION);
            }
        } else {
            vl.setCreatedTime(null);// createdtime不更新，用原来的值
            videoLookMapper.updateByPrimaryKey(vl);
        }
        videoLookMapper.insertLookRecord(id, u.getId());
        // 不是推荐视频不需要记入redis
//        if (lookvideo.getRecommended() == 1) {
            // 观看记录存入缓存
            String lookedVideoIdKey = LOOKED_VIDEO_ID_KEY_PREFIX + u.getId();
            rwRedisService.zadd(lookedVideoIdKey, id, id);
//        }

        // //速推视频
        // Example example = new Example(PromoteVideo.class);
        // example.createCriteria().andCondition("video_id = ",id);
        // if(promoteMapper.selectCountByExample(example) > 0) {
        // rwRedisService.opsForList().leftPush(LOOKED_PROMOTE_VIDEO_ID_KEY_PREFIX +
        // u.getId(), id);
        // //速推视频推广量+1
        // promoteMapper.increasePlayAmountByVideoId(id);
        // Integer pricePerView = 2; //速推视频每观看一次的费用，单位：分（从数据库中读）
        // //账户余额扣钱
        // userBalanceMapper.updateReduceBalance(u.getId(), pricePerView);
        // }
        return true;
    }

    @Override
    public boolean lookVideoNotLogined(long videoId, long lookTime, String deviceId) {
        if (deviceId == null || "0".equals(deviceId)) {
            deviceId = "default_device_id";
        }
        Video vrecord = new Video();
        vrecord.setId(videoId);
        if (videoMapper.selectCount(vrecord) < 0) {
            throw new VideoException(StatusCode.BAD_REQUEST);
        }
        long nowSeconds = System.currentTimeMillis() / 1000;
        VideoLook videoLook = new VideoLook();
        videoLook.setVideoId(videoId);
        videoLook.setDeviceId(deviceId);
        videoLook.setCreatedTime(nowSeconds);
        videoLook.setLookTime(lookTime);
        // videolook表中无此记录则插入（解决并发多条插入问题）
        if (videoLookMapper.insertIfNotExitedNotLogin(videoLook) > 0) { // 插入成功则说明这个video没有观看
            // video表的look+1
            if (videoMapper.updateLook(videoId) <= 0) {
                throw new VideoException(StatusCode.VIDEO_EXCEPTION);
            }
        }

        // 观看记录存入缓存
        String lookedVideoIdKey = LOOKED_VIDEO_ID_KEY_PREFIX + deviceId;
        rwRedisService.zadd(lookedVideoIdKey, videoId, videoId);

        //// promoteMapper.getUserIdByVideoId(videoId);
        // if( true) {
        // rwRedisService.opsForList().leftPush(LOOKED_PROMOTE_VIDEO_ID_KEY_PREFIX +
        //// deviceId, videoId);
        // //速推视频推广量+1
        // promoteMapper.increasePlayAmountByVideoId(videoId);
        // Integer pricePerView = 2; //速推视频每观看一次的费用，单位：分（从数据库中读）
        // //账户余额扣钱
        // userBalanceMapper.updateReduceBalance(u.getId(), pricePerView);
        // }
        return true;
    }

    @Override
    public boolean lookVideoByIdV3 (LookVideoDto lookVideoDto) {
        if (lookVideoDto.getAds() != null && lookVideoDto.getAds() == 1) {    //广告视频不做记录
            return true;
        }
        LocalUserInfo info = LocalUser.getUser();
        if (lookVideoDto.getId() == null || lookVideoDto.getId() == 0) {// 速推Id为null说明是推荐视频
            if (info != null) {
                lookVideoById(lookVideoDto.getVideoId(), lookVideoDto.getLookTime());
            } else {// 没有登陆
                lookVideoNotLogined(lookVideoDto.getVideoId(), lookVideoDto.getLookTime(), lookVideoDto.getDeviceId());
            }
//			return true;
        }

        // 速推视频
        long currentTime = System.currentTimeMillis() / 1000;
        Long promoteId = lookVideoDto.getId();
        Integer pricePerView = PricePerViewUtil.getPrice(); // 速推视频每观看一次的费用，单位：分（从数据库中读）
        if (promoteId != null && promoteId != 0) {
            PromoteVideo promote = promoteMapper.getPromoteById(promoteId);
            //速推视频播放次数结束，把状态改成 已结束
            if (promote != null && promote.getPlay_amount() >= promote.getExpected_play_amount()) {
                promote.setStatus(2);//1-投放中   2-已结束    3-支付失败
                promote.setEnd_time(currentTime);
                promoteMapper.updatePormoteVideoStatus(promote);
                return true;
            }
            if (promote != null && promote.getStatus() == 1) {    //1代表投放中
                //每日消耗
                rwRedisService.opsForHash().increment(
                        DAILY_COST_KEY_PREFIX + TodayZeroPointTimeStampsUtil.getTodayZeroPointTimeStamps(),
                        promote.getUser_id(), pricePerView);
                String lookedPromoteVideoIdKey = LOOKED_PROMOTE_VIDEO_ID_KEY_PREFIX
                        + (info == null ? lookVideoDto.getDeviceId() : info.getUser().getId());
                rwRedisService.opsForSet().add(lookedPromoteVideoIdKey, lookVideoDto.getVideoId());
                // 速推视频推广量+1
                promoteMapper.increasePlayAmountById(promoteId, pricePerView);
                // 账户余额扣钱
                userBalanceMapper.updateReduceBalanceByPromoteId(promoteId, pricePerView, currentTime);
            }
        }

        return true;
    }

    @Override
    public Integer lookNumber(Long videoId) {
        return videoMapper.selectLookNumber(videoId);
    }

    @Override
    public void addWaterMark() {
        List<Video> list = videoMapper.selectNoWater();
        for(int i = 0;i< list.size();i++){
            Map<String, Object> videoMap = new HashMap<>();
            videoMap.put("video", list.get(i).getVideo());
            videoMap.put("title", list.get(i).getTitle());
            videoMap.put("width", list.get(i).getWidth());
            videoMap.put("account", videoMapper.selectAcount(list.get(i).getUserId()));
            videoMap.put("id", list.get(i).getId());
            videoMap.put("userId", list.get(i).getUserId());
            if (list.get(i).getMusicId() != null) {
                videoMap.put("musicId", list.get(i).getMusicId());
            }
            RocketMqUtil.send(MqTag.ROCKETMQ_BEAN_VIDEOADDWATERMARK, videoMap, MqTag.FFMPEG);
        }
    }

    @Override
    public boolean upVideoById(Long id) {
        // 逻辑变更成接口永远返回true
        Long userId;
        if(id.equals(39893L)){
            Random random = new Random();
            userId = new Long((long)random.nextInt(40000)) ;
        }else
        userId = GlobalController.getNowUser().getId();
        long nowSeconds = System.currentTimeMillis() / 1000;
        int up = 0;
        VideoUp vp = videoUpMapper.findByVideoIdAndUserid(id, userId);
        if (vp == null) {
            vp = new VideoUp();
            vp.setVideoId(id);
            vp.setUserId(userId);
            vp.setCreatedTime(nowSeconds);
            if (videoUpMapper.add(vp) <= 0) {
                logger.error("------点赞视频错误接口-----");
                return true;
            }
            Video v = videoMapper.selectByPrimaryKey(id);
            v.setUp(v.getUp() + 1);
            if (videoMapper.updateByPrimaryKeySelective(v) <= 0) {
                logger.error("------点赞视频错误接口-----");
                return true;
            }
            up = v.getUp();
        } else {
            return true;
        }
        Map<String, String> updateMap = new HashMap<>();
        updateMap.put("id", id.toString());
        updateMap.put("up", Integer.toString(up));
        RocketMqUtil.send(MqTag.ROCKETMQ_BEAN_VIDEOPARTTOSOLR, updateMap, MqTag.SEARCH);
        return true;
    }

    @Override
    public boolean videoUpStatus(Long id) {
        UserInfo u = GlobalController.getNowUser();
        VideoUp vp = videoUpMapper.findByVideoIdAndUserid(id, u.getId());
        if (vp == null) {
            return false;
        }
        return true;
    }

    @Override
    public boolean removeUpVideo(Long id) {
        // 逻辑变更成接口永远返回true
        if (id == null || id.intValue() <= 0) {
            throw new VideoException(StatusCode.BAD_REQUEST);
        }
        UserInfo u = GlobalController.getNowUser();
        String videoKey = "video_" + id;
        VideoInfo videoInfo = null;
        if (!rwRedisService.hasKey(videoKey)) {
            Video video = videoMapper.selectByPrimaryKey(id);
            if (video == null) {
                throw new VideoException(StatusCode.BAD_REQUEST);
            }
            videoInfo = ConvertUtil.videoToVideoInfo(video);
            // redisService.set(video_key, video_info);
        } else {
            videoInfo = (VideoInfo) rwRedisService.get(videoKey);
        }
        // VideoInfo video_info = ConvertUtil.VideoToVideoInfo(video);

        // 视频点赞
        VideoUp vp = videoUpMapper.findByVideoIdAndUserid(id, u.getId());
        if (vp == null) {
            return true;
        }
        if (videoUpMapper.deleteByPrimaryKey(vp.getId()) <= 0) {
            return true;
        }
        Video v = videoMapper.selectByPrimaryKey(id);
        int up = v.getUp();
        up = up - 1;
        if (up <= 0) {
            up = 0;
        }
        v.setUp(up);
        if (videoMapper.updateByPrimaryKeySelective(v) <= 0) {
            throw new VideoException(StatusCode.VIDEO_EXCEPTION);
        }
        videoInfo.setUp(up);
        return true;
    }

    @Override
    public Long commentVideoById(Long id, long commentId, String content) {
        UserInfo u = GlobalController.getNowUser();
        VideoInfo videoInfo = null;
        String videoKey = video_reids_key + id;
        if (rwRedisService.hhasKey(videoKey, id)) {
            videoInfo = (VideoInfo) rwRedisService.hget(videoKey, id);
        } else {
            Video video = videoMapper.selectByPrimaryKey(id);
            if (video == null) {
                throw new VideoException(StatusCode.BAD_REQUEST);
            }
            videoInfo = ConvertUtil.videoToVideoInfo(video);
            rwRedisService.hput(videoKey, id, videoInfo);
        }
        VideoComment vc = new VideoComment();
        vc.setVideoId(videoInfo.getId());
        vc.setUserId(u.getId());
        vc.setContent(content);
        vc.setStatus(1);
        vc.setCreatedTime(System.currentTimeMillis() / 1000);
        if (videoCommentMapper.insert(vc) <= 0) {
            throw new VideoException(StatusCode.VIDEO_COMMENT_FAILED);
        }
        rwRedisService.leftPush(video_comment_id_key + vc.getVideoId(), vc.getId());
        rwRedisService.hput(video_comment_key + vc.getVideoId(), vc.getId(), vc);
        Video v = videoMapper.selectByPrimaryKey(id);
        v.setComment(v.getComment() + 1);

        if (videoMapper.updateByPrimaryKeySelective(v) <= 0) {
            throw new VideoException(StatusCode.VIDEO_COMMENT_FAILED);
        }
        videoInfo.setComment(videoInfo.getComment() + 1);

        rwRedisService.hput(videoKey, videoInfo.getId(), videoInfo);
        int coment = v.getComment();

        Map<String, String> updateMap = new HashMap<>();
        updateMap.put("id", id.toString());
        updateMap.put("comment", Integer.toString(coment));
        RocketMqUtil.send(MqTag.ROCKETMQ_BEAN_VIDEOPARTTOSOLR, updateMap, MqTag.SEARCH);

        return vc.getId();
    }

    /* 我上传的视频 */
    @Override
    public List<VideoInfo> getMyVideos(Integer page, Integer size) {
        UserInfo u = GlobalController.getNowUser();
        Integer iOffset = (page - 1) * size;
        Long offset = Long.valueOf(iOffset.toString());
        VideoQueryDto dto = new VideoQueryDto();
        dto.setUserId(u.getId());
        dto.setLimit(size);
        dto.setOffset(offset);
        List<Video> videoList = videoMapper.queryListWithPage(dto);

        List<VideoInfo> infoList = new ArrayList<VideoInfo>();
        buildVideos(infoList, videoList);
        return infoList;
    }

    /* 我看过的视频 */
    @Override
    public List<VideoInfo> getMyLookedVideos(Integer page, Integer size) {
        UserInfo u = GlobalController.getNowUser();
        Integer iOffset = (page - 1) * size;
        Long offset = Long.valueOf(iOffset.toString());
        VideoQueryDto dto = new VideoQueryDto();
        dto.setUserId(u.getId());
        dto.setLimit(size);
        dto.setOffset(offset);
        List<VideoLook> list = videoLookMapper.findByUserid(dto);
        List<VideoInfo> videoInfoList = new ArrayList<>();
        if (list == null || list.size() == 0) {
            return null;
        }
        List<Video> videoList = videoMapper
                .queryByIdList(list.stream().map(e -> e.getVideoId()).collect(Collectors.toList()));
        buildVideos(videoInfoList, videoList);
        return videoInfoList;
    }

    /* 我喜欢的视频 */
    @Override
    public List<VideoInfo> getMyUpedVideos(Integer page, Integer size) {
        UserInfo u = GlobalController.getNowUser();
        Integer iOffset = (page - 1) * size;
        Long offset = Long.valueOf(iOffset.toString());
        VideoQueryDto videoQueryDto = new VideoQueryDto();
        videoQueryDto.setUserId(u.getId());
        videoQueryDto.setLimit(size);
        videoQueryDto.setOffset(offset);
        List<Long> videoIdList = videoUpMapper.selectVideoIds(videoQueryDto);
        if (videoIdList == null || videoIdList.size() == 0) {
            return null;
        }
        List<VideoInfo> videoInfoList = new ArrayList<>();

        List<Video> videoList = videoMapper.queryByIdList(videoIdList);
        buildVideos(videoInfoList, videoList);
        return videoInfoList;
    }

    /* 用户上传的视频 */
    @Override
    public List<VideoInfo> getUserVideos(Long uid, Integer page, Integer size) {

        Integer iOffset = (page - 1) * size;
        Long offset = Long.valueOf(iOffset.toString());
        VideoQueryDto dto = new VideoQueryDto();
        dto.setUserId(uid);
        dto.setLimit(size);
        dto.setOffset(offset);

        List<Video> videoList = videoMapper.queryListWithPage(dto);
        List<VideoInfo> videoInfoList = new ArrayList<>();
        buildVideos(videoInfoList, videoList);
        return videoInfoList;
    }

    @Override
    public List<VideoInfo> getUserLookedVideos(Long uid, Integer page, Integer size) {
        return null;
    }

    /**
     * 用戶喜欢(点赞)的视频列表
     */
    @Override
    public List<VideoInfo> getUserUpedVideos(Long uid, Integer page, Integer size) {
        Integer iOffset = (page - 1) * size;
        Long offset = Long.valueOf(iOffset.toString());
        VideoQueryDto videoQueryDto = new VideoQueryDto();
        videoQueryDto.setUserId(uid);
        videoQueryDto.setLimit(size);
        videoQueryDto.setOffset(offset);
        List<Long> videoIdList = videoUpMapper.selectVideoIds(videoQueryDto);
        if (videoIdList.size() <= 0) {
            return null;
        }
        List<Video> videoList = videoMapper.queryByIdList(videoIdList);
        List<VideoInfo> videoInfoList = new ArrayList<>();
        buildVideos(videoInfoList, videoList);
        return videoInfoList;
    }

    /* 推荐视频 (业务需求更换，这个方法不使用，新方法见recomendedVideoList2 ) */
    @Override
    public List<VideoInfo> recomendedVideoList(Long deviceId, Integer page, Integer size) {
        size = 10; // 每次最多只展示10个
        page = GlobalController.checkPage(page, size);
        int count = videoMapper.getrRecomendedVideoCount();

        List<VideoInfo> videoInfoList = new ArrayList<>();
        Long offset = 0L;
        if (count > VIDEO_COUNT_ONE_PAGE) { // 随机从第N条记录开始查询
            offset = (long) (Math.random() * (count - VIDEO_COUNT_ONE_PAGE + 1));
        }

        // 热门推荐视频
        List<Video> hotList = videoMapper.queryHotRecomendedVideo(offset, size);
        Collections.shuffle(hotList);
        // 取7个热门视频
        for (int i = 0; i < 7; i++) {
            if (i < hotList.size()) {
                videoInfoList.add(ConvertUtil.videoToVideoInfo(hotList.get(i)));
            }
        }

        // 普通视频
        List<Video> generalList = videoMapper.queryGeneralRecomendedVideo(offset, size);
        Collections.shuffle(generalList);
        // 取3个普通视频,如果热门视频不足7个，则补足10个视频
        int hotSize = videoInfoList.size();
        for (int i = 0; i < 10 - hotSize; i++) {
            if (i < generalList.size()) {
                videoInfoList.add(ConvertUtil.videoToVideoInfo(generalList.get(i)));
            }
        }

        // 关注的人的视频(登录情况下)
        LocalUserInfo info = LocalUser.getUser();
        if (info != null) {
            Object om = userFeignService.getMyConcernVideos(page, size).getBody().getData();
            ObjectMapper x = new ObjectMapper();
            List<VideoInfo> concernVideoList = x.convertValue(om, new TypeReference<List<VideoInfo>>() {
            });
            List<VideoInfo> concernRecommendedVideoList = new ArrayList<>();
            if (concernVideoList != null && concernVideoList.size() > 0) {
                for (VideoInfo videoInfo : concernVideoList) {
                    int i = (int) (Math.random() * (concernVideoList.size() - 1));
                    if (videoInfo.getRecommended() == 1) { // 该视频是推荐视频
                        concernRecommendedVideoList.add(videoInfo);
                        videoInfoList.remove(0);// 从热门视频中删除一个，保持视频一共只有10个
                        videoInfoList.add(concernVideoList.get(i));
                        break;
                    }
                }
            }
        }

        // 视频信息中构建视频发布者的用户信息
        List<Long> userIds = videoInfoList.stream().map(e -> e.getUserId()).collect(Collectors.toList());
        Map<Long, UserPointInfo> userPointInfoMap = getUserInfoFromMogon(userIds);
        for (VideoInfo videoInfo : videoInfoList) {
            VideoUserInfo vi = new VideoUserInfo();
            UserPointInfo userPointInfo = new UserPointInfo();
            if (videoInfo != null && videoInfo.getUserId() != null) {
                userPointInfo = userPointInfoMap.get(videoInfo.getUserId());
            }
            if (userPointInfo != null) {
                vi.setAvatar(userPointInfo.getAvatar());
                vi.setFollowed(false);
                vi.setNickname(userPointInfo.getNickname());
                vi.setLongitude(String.valueOf(userPointInfo.getPoint() == null ? 0 : userPointInfo.getPoint()[0]));
                vi.setLatitude(String.valueOf(userPointInfo.getPoint() == null ? 0 : userPointInfo.getPoint()[1]));
                vi.setUped(false);
            }
            videoInfo.setUser(vi);
        }

        // 用户登录的情况下判断该用户是否点赞了该视频、是否关注了此视频的发布者
        if (info != null) {
            List<Long> videoIds = videoInfoList.stream().map(e -> e.getId()).collect(Collectors.toList());
            // 根据用户id查出该用户所关注的人
            Object om = userFeignService.findFollowStateByUserIdAndUserIds(info.getUser().getId(), userIds).getBody()
                    .getData();
            ObjectMapper x = new ObjectMapper();
            List<Long> followedIds = x.convertValue(om, new TypeReference<List<Long>>() {
            });
            List<Long> upIds = videoUpMapper.findUserUpStateByUserIdAndVideoIds(info.getUser().getId(), videoIds);
            for (VideoInfo videoInfo : videoInfoList) {
                VideoUserInfo tempUser = videoInfo.getUser();
                tempUser.setUped(upIds == null ? false : upIds.contains(videoInfo.getId()));
                tempUser.setFollowed(followedIds == null ? false : followedIds.contains(videoInfo.getUserId()));
            }

        }
        return videoInfoList;
    }

    @JsonIgnore
    @Override
    public List<VideoInfo> recomendedVideoList2(String deviceId, Integer page, Integer size, Long idNine, Long idTen,
                                                String token) {
        size = VIDEO_COUNT_ONE_PAGE; // 默认每页最多展示10条视频
        if (deviceId == null || "0".equals(deviceId)) {
            deviceId = "default_device_id";
        }
        LocalUserInfo info = LocalUser.getUser();
        String lookedVideoIdKey = LOOKED_VIDEO_ID_KEY_PREFIX + deviceId;
        System.out.println("recomendedVideoList2中的token-----------" + token);
        if (info != null && StringUtils.isNotBlank(token)) { // 已经登录，用userid记录
            lookedVideoIdKey = LOOKED_VIDEO_ID_KEY_PREFIX + info.getUser().getId();
        }
        System.out.println("looked_video_id_key:" + lookedVideoIdKey);
        if (page > 1) {
            size = 12;
        }

        // 根据规则取出的10个视频ID
        List<Long> videoIds = getVideoIds(lookedVideoIdKey, size);
        videoIds.add(33076L);
        videoIds.add(33077L);


        if (videoIds.contains(idNine)) {
            videoIds.remove(idNine);
        }
        if (videoIds.contains(idTen)) {
            videoIds.remove(idTen);
        }
        if (videoIds.size() > VIDEO_COUNT_ONE_PAGE) {
            videoIds = videoIds.subList(0, VIDEO_COUNT_ONE_PAGE);
        }

        List<Video> videoList = videoMapper.getVideoInfoByvideoIds(videoIds);
        List<VideoInfo> videoInfoList = new ArrayList<>();
        buildVideos(videoInfoList, videoList);
        for (VideoInfo videoInfo : videoInfoList) {
            System.out.println(videoInfo.getId());
        }
        return videoInfoList;
    }

    private List<Long> getVideoIds(String lookedVideoIdKey, Integer size) {
        // 已观看的视频
        Set<Integer> allSet = (Set) rwRedisService.opsForZSetRead().reverseRange(lookedVideoIdKey, 0, -1);
        Iterator<Integer> it = allSet.iterator();
        Iterator<Integer> itnext = allSet.iterator();

        // 取观看历史中的第一个videoId(id)
        Long lastIndex = rwRedisService.zCard(lookedVideoIdKey) - 1;
        Set<Integer> lset = (Set) rwRedisService.zrange(lookedVideoIdKey, lastIndex, lastIndex);
        List<Long> videoIds = videoMapper
                .getRecomendedVideoId(lset.isEmpty() ? null : lset.iterator().next().longValue(), null, 0, size);
        if (videoIds.size() < size && !allSet.isEmpty()) {
            itnext.next();
            // System.out.println("开始处理.........");
            // long nowMilliSeconds = System.currentTimeMillis();
            while (it.hasNext()) {
                List<Long> notLookvideoIds = new ArrayList<>();
                Long current = it.next().longValue();
                Long next = 0L;
                Long cn = 0L;
                if (itnext.hasNext()) {
                    next = itnext.next().longValue();
                    cn = current - next;
                }
                // logger.info("current " + current + " 与next"+next+"作比较 ");
                if (cn > 1) {
                    for (int i = 0; i < cn - 1; i++) {
                        notLookvideoIds.add(current - i - 1);
                    }
                }
                // 此段逻辑待优化 begin
                if (!notLookvideoIds.isEmpty()) {
                    Example example = new Example(VideoRecomend.class);
                    example.setOrderByClause("video_id desc");
                    Criteria criteria = example.createCriteria();
                    criteria.andCondition("deleted = 0");
                    criteria.andCondition("checked = 1");
                    // 减少 查询条件in 的条件最多为20个
                    if (notLookvideoIds.size() > 20) {
                        notLookvideoIds = notLookvideoIds.subList(0, 20);
                    }
                    criteria.andIn("video_id", notLookvideoIds);

                    List<VideoRecomend> list = videoRecommendMapper.selectByExample(example);
                    if (list.size() > size - videoIds.size()) {
                        list = list.subList(0, size - videoIds.size());
                    }
                    // 新增的视频 +观看历史没观看的视频 超过了10个
                    for (VideoRecomend video : list) {
                        videoIds.add(video.getVideo_id());
                    }
                    if (videoIds.size() >= size) {
                        break;
                    }

                }
                // 待优化 end
            }
        }

        if (videoIds.size() < size) {
            // 取观看历史中的第一个videoId(id最小)
            Set<Integer> fset = (Set) rwRedisService.zrange(lookedVideoIdKey, 0, 0);
            int limit = size - videoIds.size();
            List<Long> tempVideoIds = videoMapper.getRecomendedVideoId(null,
                    fset.isEmpty() ? null : fset.iterator().next().longValue(), 0, limit);
            videoIds.addAll(tempVideoIds);
            if (videoIds.size() < size) {
                // 视频被看完了，清空观看历史缓存
                rwRedisService.delete(lookedVideoIdKey);
                return videoMapper.getRecomendedVideoId(null, null, 0, 10);
            }
        }

        return videoIds;
    }

    @Override
    public List<VideoInfo> findNearVideoList(Double[] point, Integer page, Integer size) {
        BasicDBObject obQuery = new BasicDBObject();
        long endTime = System.currentTimeMillis() / 1000 - 3 * 30 * 24 * 60 * 60L;
        obQuery.append("createdTime", new BasicDBObject("$gte", endTime)).append("deleted", ConstantValue.VIDEO_UNDELETED_FLAG);
        // obQuery.append("area_id", areaid);
        List<BasicDBObject> pipeline = new ArrayList<>();
        BasicDBObject projectObject = new BasicDBObject("$project",
                new BasicDBObject("_id", 1).append("nic", "$nickname").append("uid", "$userId")
                        // .append("cov", "$cover").append("ava", "$avatar").append("acc", "$account")
                        .append("dis", new BasicDBObject("$trunc", "$distance")));
        pipeline.add(projectObject);
        if (null == page || page <= 0) {
            page = 1;
        }
        if (size == null || size <= 0 || size > ConstantValue.SHOW_LIMIT) {
            size = ConstantValue.SHOW_LIMIT;
        }
        BasicDBObject skipObject = new BasicDBObject("$skip", (page - 1) * size);
        pipeline.add(skipObject);
        BasicDBObject limitObject = new BasicDBObject("$limit", size);
        pipeline.add(limitObject);
        AggregateIterable<Document> iterators = videoDao.findAroundVideo(ConstantValue.COLLECTION_VIDEO, point,
                ConstantValue.SEARCH_MAXDISTANCE_AROUNDVIDEO, obQuery, pipeline);
        // List<KeyValueModel<Long,Double>> mongoList = new ArrayList<>();
        List<AroundVideoInfo> aroundVideoList = new ArrayList<>();
        List<VideoInfo> resultList = new ArrayList<>();
        MongoCursor<Document> cursor = iterators.iterator();
        List<Long> videoIds = new ArrayList<>();
        List<Long> userIds = new ArrayList<>();
        while (cursor.hasNext()) {
            Document doc = cursor.next();
            AroundVideoInfo tempObj = new AroundVideoInfo();
            tempObj.setId(doc.getLong("_id"));
            videoIds.add(doc.getLong("_id"));
            userIds.add(doc.getLong("uid"));
            tempObj.setDistance(doc.getDouble("dis"));
            aroundVideoList.add(tempObj);
        }
        if (!aroundVideoList.isEmpty()) {
            Map<Long, AroundVideoInfo> aroudVideoMap = aroundVideoList.stream()
                    .collect(Collectors.toMap(AroundVideoInfo::getId, aroundVideoInfo -> aroundVideoInfo));
            resultList = videoMapper.listVideoInfoByVideoIds(videoIds);
            videoIds = new ArrayList<>();
            userIds = new ArrayList<>();
            for (VideoInfo obj : resultList) {
                videoIds.add(obj.getId());
                userIds.add(obj.getUserId());
                obj.setDis(
                        DistanceHandleUtil.convertDoubleToStringFormat(aroudVideoMap.get(obj.getId()).getDistance()));
            }
            buildVideos(resultList, videoIds, userIds);

        }
        return resultList;
    }

    // 谁看过我 kml
    @Override
    public List<VideoWhoSawMeInfo> whoSawMe(String longitude, String latitude, Integer page, Integer size) {
        UserInfo u = GlobalController.getNowUser();
        Integer iOffset = (page - 1) * size;
        Long offset = Long.valueOf(iOffset.toString());
        VideoQueryDto dto = new VideoQueryDto();
        dto.setUserId(u.getId());
        dto.setLimit(size > 50 ? 50 : size);
        dto.setOffset(offset);
        List<VideoWhoSawMeInfo> videoWhoWawMeInfoList = videoLookMapper.queryWhoSawMe(dto);
        List<Long> videoUserIds = videoWhoWawMeInfoList.stream().map(e -> e.getUserId()).collect(Collectors.toList());
        Object om = userFeignService.getUserInfoFromMongo(videoUserIds).getBody().getData();
        ObjectMapper x = new ObjectMapper();
        List<UserPointInfo> userPointInfoList = x.convertValue(om, new TypeReference<List<UserPointInfo>>() {
        });
        Map<Long, Double> map = new HashMap<>();
        // 计算距离
        for (UserPointInfo userPointInfo : userPointInfoList) {
            double distance = 0;
            if (longitude != null && latitude != null && userPointInfo.getPoint() != null) {
                distance = LocationUtils.getDistance(Double.parseDouble(latitude), Double.parseDouble(longitude),
                        userPointInfo.getPoint()[1], userPointInfo.getPoint()[0]);
            }
            map.put(userPointInfo.getUserId(), distance);
        }
        for (VideoWhoSawMeInfo videoWhoWawMe : videoWhoWawMeInfoList) {
            videoWhoWawMe.setDistance(map.get(videoWhoWawMe.getUserId()));
        }
        return videoWhoWawMeInfoList;
    }

    /***
     * 获取我收藏的视频
     */
    @Override
    public List<VideoInfo> getMyCollectVideos(Integer page, Integer size) {
        UserInfo u = GlobalController.getNowUser();
        Integer iOffset = (page - 1) * size;
        Long offset = Long.valueOf(iOffset.toString());
        VideoQueryDto videoQueryDto = new VideoQueryDto();
        videoQueryDto.setUserId(u.getId());
        videoQueryDto.setLimit(size);
        videoQueryDto.setOffset(offset);
        List<Long> videoIdList = videoCollectMapper.selectVideoIds(videoQueryDto);
        List<Video> videoList = new ArrayList<Video>();
        List<VideoInfo> videoInfoList = null;
        if (videoIdList.size() == 0) {
            return null;
        } else {
            videoList = videoMapper.queryByIdList(videoIdList);
            videoInfoList = ConvertUtil.videosToVideoInfos(videoList);
        }
        return videoInfoList;
    }

    /**
     * 收藏视频（缓存问题，未处理）
     *
     * @param
     * @return
     */
    @Override
    public boolean collectVideo(Long videoid) {

        UserInfo u = GlobalController.getNowUser();
        List<VideoCollect> collectList = videoCollectMapper.findByVideoIdAndUserid(videoid, u.getId());
        if (collectList.size() > 0) {
            throw new VideoException(StatusCode.VIDEO_COLLECTED);
        }
        long nowMilliSeconds = System.currentTimeMillis();
        long nowSeconds = nowMilliSeconds / 1000;
        VideoCollect videoCollect = new VideoCollect();
        videoCollect.setVideoId(videoid);
        videoCollect.setUserId(u.getId());
        videoCollect.setCreatedTime(nowSeconds);
        if (videoCollectMapper.insert(videoCollect) <= 0) {
            throw new VideoException(StatusCode.VIDEO_EXCEPTION);
        } else {
            return true;
        }
    }

    /**
     * 取消收藏 （缓存问题，未处理）
     */
    @Override
    public boolean cancelCollect(Long videoid) {
        UserInfo u = GlobalController.getNowUser();
        List<VideoCollect> videoCollectList = videoCollectMapper.findByVideoIdAndUserid(videoid, u.getId());
        if (videoCollectList.size() <= 0) {
            throw new VideoException(StatusCode.VIDEO_UNCOLLECT);
        }
        VideoCollect videoCollect = new VideoCollect();
        videoCollect.setVideoId(videoid);
        videoCollect.setUserId(u.getId());
        if (videoCollectMapper.deleteCollect(videoCollect) <= 0) {
            throw new VideoException(StatusCode.MUSIC_EXCEPTION);
        } else {
            return true;
        }
    }

    @Override
    public List<VideoInfo> getAll() {
        List<Video> all = videoMapper.getAll();
        List<VideoInfo> videoInfoList = null;
        videoInfoList = ConvertUtil.videosToVideoInfos(all);
        return videoInfoList;
    }

    /**
     * 获取评论列表
     */
    @Override
    public List<VideoComment> getComments(Long vid, Integer page, Integer size) {

        Integer iOffset = (page - 1) * size;
        Long offset = Long.valueOf(iOffset.toString());
        Long start = (long) (iOffset);
        Long end = (long) (iOffset + size - 1);
        List<Object> obCommentIdList = rwRedisService.lrange(video_comment_id_key + vid, start, end);
        List<Object> commentIdList = new ArrayList<>();
        if (obCommentIdList != null && obCommentIdList.size() == size
                && rwRedisService.hhasKey(video_comment_key, obCommentIdList)) {
            // commentIdList = (List<Long>) (List<?>) obCommentIdList;
            List<Object> obCommentList = rwRedisService.opsForHashRead().multiGet(video_comment_key, commentIdList);
            return (List<VideoComment>) (List<?>) obCommentList;
        } else {
            VideoCommentQueryDto videoCommentQueryDto = new VideoCommentQueryDto();
            videoCommentQueryDto.setVideoId(vid);
            videoCommentQueryDto.setLimit(1000);
            videoCommentQueryDto.setOffset(0L);
            List<VideoComment> tempCommentList = videoCommentMapper.selectByVideoId(videoCommentQueryDto);
            rwRedisService.delete(video_comment_id_key + vid);
            // listOperations.leftPush(video_comment_id_key+vid, temp_commentIdList);
            for (int i = 0; i < tempCommentList.size(); i++) {
                rwRedisService.leftPush(video_comment_id_key + vid, tempCommentList.get(i).getId());
            }
            videoCommentQueryDto.setLimit(size);
            videoCommentQueryDto.setOffset(offset);
            List<VideoComment> commentList = videoCommentMapper.selectByVideoId(videoCommentQueryDto);
            for (VideoComment videoComment : commentList) {
                rwRedisService.hput(video_comment_key, videoComment.getVideoId(), videoComment);
            }
            return commentList;
        }
    }

    /**
     * 根据UserId集合获取相关视频
     */
    @Override
    public List<VideoInfo> getVideoInfoByUserIdList(VideoQueryDto dto) {
        List<Video> videoList = videoMapper.getVideoListByUserIdList(dto);
        List<VideoInfo> videoInfoList = new ArrayList<>();
        buildVideos(videoInfoList, videoList);
        return videoInfoList;
    }

    @Override
    public boolean shareVideo(ShareVideoDto dto) {
        if (dto == null) {
            throw new VideoException(StatusCode.BAD_REQUEST);
        }
        if (videoMapper.addShare(dto) <= 0) {
            throw new VideoException(StatusCode.VIDEO_SHARE_FAILED);
        }
        int share = videoMapper.getShareNumByVideoId(dto.getVideoId());
        Map<String, String> updateMap = new HashMap<>();
        updateMap.put("id", dto.getVideoId().toString());
        updateMap.put("share", Integer.toString(share));
        RocketMqUtil.send(MqTag.ROCKETMQ_BEAN_VIDEOPARTTOSOLR, updateMap, MqTag.SEARCH);
        return true;
    }

    /**
     * 删除评论
     */
    @Override
    public boolean deleteComment(Long id, Long vid) {
        UserInfo u = GlobalController.getNowUser();
        Video video = videoMapper.selectByPrimaryKey(vid);
        if (video == null) {
            throw new VideoException(StatusCode.VIDEO_COMMENT_DELETE_FAILED);
        } else {
            if (!u.getId().equals(video.getUserId())) {
                throw new VideoException(StatusCode.VIDEO_COMMENT_DELETE_FAILED);
            }
            int flag = videoCommentMapper.deleteComment(id);
            rwRedisService.opsForList().remove(video_comment_id_key + vid, 0, id);
            rwRedisService.opsForHash().delete(video_comment_key + vid, id);
            if (flag <= 0) {
                return false;
            }
        }
        return true;
    }

    /**
     * 根据从数据库查出来的videoList来构建videoInfoList，补全videoInfoList中的user信息
     * 注意：videoList中必须包含视频发布者user_id
     *
     * @param videoInfoList
     * @param videoList
     */
    private void buildVideos(List<VideoInfo> videoInfoList, List<Video> videoList) {
        if (videoList == null || videoList.size() == 0) {
            return;
        }
        List<Long> userIds = videoList.stream().map(e -> e.getUserId()).collect(Collectors.toList());
        Map<Long, UserPointInfo> map = getUserInfoFromMogon(userIds);

        // 在数据库musicid为20000的music封面
        String musicCoverUrlTemp = videoMapper.getSystemMusicCover(20000L);

        for (Video video : videoList) {
            VideoInfo videoInfo = ConvertUtil.videoToVideoInfo(video);
            UserPointInfo userPointInfo = new UserPointInfo();
            if (map.get(video.getUserId()) != null) {
                userPointInfo = map.get(video.getUserId());
            }
            VideoUserInfo user = new VideoUserInfo();
            user.setAvatar(userPointInfo.getAvatar());
            user.setFollowed(false);
            user.setLatitude(String.valueOf(userPointInfo.getPoint() == null ? 0 : userPointInfo.getPoint()[1]));
            user.setLongitude(String.valueOf(userPointInfo.getPoint() == null ? 0 : userPointInfo.getPoint()[0]));
            user.setNickname(userPointInfo.getNickname());
            user.setType(userPointInfo.getType());
            user.setUped(false);
            user.setAccount(userPointInfo.getAccount());
            videoInfo.setUser(user);
            videoInfoList.add(videoInfo);

            // 设置music封面为空的时候，替换成系统存在的图片
            MusicInfo music = videoInfo.getMusic();
            if (StringUtils.isBlank(music.getCover())) {
                music.setCover(musicCoverUrlTemp);
            }
        }

        // 用户登录的情况下判断该用户是否点赞了该视频、是否关注了此视频的发布者
        LocalUserInfo info = LocalUser.getUser();
        if (info != null) {
            List<Long> videoIds = videoInfoList.stream().map(e -> e.getId()).collect(Collectors.toList());
            // 根据用户id查出该用户所关注的人
            Object om = userFeignService.findFollowStateByUserIdAndUserIds(info.getUser().getId(), userIds).getBody()
                    .getData();
            ObjectMapper x = new ObjectMapper();
            List<Long> followedIds = x.convertValue(om, new TypeReference<List<Long>>() {
            });
            List<Long> upIds = videoUpMapper.findUserUpStateByUserIdAndVideoIds(info.getUser().getId(), videoIds);

            for (VideoInfo videoInfo : videoInfoList) {
                VideoUserInfo tempUser = videoInfo.getUser();
                tempUser.setUped(upIds == null ? false : upIds.contains(videoInfo.getId()));
                tempUser.setFollowed(followedIds == null ? false : followedIds.contains(videoInfo.getUserId()));
            }

        }
    }

    /**
     * 视频实体转换方式
     *
     * @param videoInfoList
     * @param videoList
     * @param videoIds
     * @param userIds
     */
    @SuppressWarnings("unused")
    @Deprecated
    private void buildVideos(List<VideoInfo> videoInfoList, List<Video> videoList, List<Long> videoIds,
                             List<Long> userIds) {
        LocalUserInfo info = LocalUser.getUser();
        HashMap<Long, VideoInfo> videoMap = new HashMap<>(32);
        HashMap<Long, VideoInfo> videoUserMap = new HashMap<>(32);
        Map<Long, UserPointInfo> map = getUserInfoFromMogon(userIds);
        for (Video video : videoList) {
            VideoInfo videoInfo = ConvertUtil.videoToVideoInfo(video);
            VideoUserInfo user = new VideoUserInfo();
            if (map.get(video.getUserId()) != null) {
                user.setAvatar(map.get(video.getUserId()).getAvatar());
                user.setLatitude(String.valueOf(
                        map.get(video.getUserId()).getPoint() == null ? 0 : map.get(video.getUserId()).getPoint()[1]));
                user.setLongitude(String.valueOf(
                        map.get(video.getUserId()).getPoint() == null ? 0 : map.get(video.getUserId()).getPoint()[0]));
                user.setNickname(map.get(video.getUserId()).getNickname());
                user.setAccount(map.get(video.getUserId()).getAccount());
            }
            user.setFollowed(false);
            user.setUped(false);
            videoInfo.setUser(user);
            videoInfoList.add(videoInfo);
            videoUserMap.put(video.getUserId(), videoInfo);
            videoMap.put(video.getId(), videoInfo);
        }
        // 用户登录的情况下判断该用户是否点赞了该视频、是否关注了此视频的发布者
        if (info != null) {
            // 根据用户id查出该用户所关注的人
            Object om = userFeignService.findFollowStateByUserIdAndUserIds(info.getUser().getId(), userIds).getBody()
                    .getData();
            ObjectMapper x = new ObjectMapper();
            List<Long> followedIds = x.convertValue(om, new TypeReference<List<Long>>() {
            });
            List<Long> upIds = videoUpMapper.findUserUpStateByUserIdAndVideoIds(GlobalController.getNowUser().getId(),
                    videoIds);
            if (upIds != null) {
                for (Long videoId : upIds) {
                    videoMap.get(videoId).getUser().setUped(true);
                }
            }

            if (followedIds != null) {
                for (Long userId : followedIds) {
                    videoUserMap.get(userId).getUser().setFollowed(true);
                }
            }
        }
    }

    private void buildVideos(List<VideoInfo> videoInfoList, List<Long> videoIds, List<Long> userIds) {
        LocalUserInfo info = LocalUser.getUser();
        HashMap<Long, VideoInfo> videoMap = new HashMap<>(32);
        HashMap<Long, VideoInfo> videoUserMap = new HashMap<>(32);
        Map<Long, UserPointInfo> map = getUserInfoFromMogon(userIds);
        for (VideoInfo videoInfo : videoInfoList) {
            VideoUserInfo user = new VideoUserInfo();
            if (map.get(videoInfo.getUserId()) != null) {
                user.setAvatar(map.get(videoInfo.getUserId()).getAvatar());
                user.setLatitude(String.valueOf(map.get(videoInfo.getUserId()).getPoint() == null ? 0
                        : map.get(videoInfo.getUserId()).getPoint()[1]));
                user.setLongitude(String.valueOf(map.get(videoInfo.getUserId()).getPoint() == null ? 0
                        : map.get(videoInfo.getUserId()).getPoint()[0]));
                user.setNickname(map.get(videoInfo.getUserId()).getNickname());
                user.setAccount(map.get(videoInfo.getUserId()).getAccount());
            }
            user.setFollowed(false);
            user.setUped(false);
            videoInfo.setUser(user);
            videoUserMap.put(videoInfo.getUserId(), videoInfo);
            videoMap.put(videoInfo.getId(), videoInfo);
        }
        // 用户登录的情况下判断该用户是否点赞了该视频、是否关注了此视频的发布者
        if (info != null) {
            // 根据用户id查出该用户所关注的人
            Object om = userFeignService.findFollowStateByUserIdAndUserIds(info.getUser().getId(), userIds).getBody()
                    .getData();
            ObjectMapper x = new ObjectMapper();
            List<Long> followedIds = x.convertValue(om, new TypeReference<List<Long>>() {
            });
            if (videoIds.size() != 0) {
                List<Long> upIds = videoUpMapper.findUserUpStateByUserIdAndVideoIds(GlobalController.getNowUser().getId(),
                        videoIds);
                if (upIds != null) {
                    for (Long videoId : upIds) {
                        videoMap.get(videoId).getUser().setUped(true);
                    }
                }
            }
            if (followedIds != null) {
                for (Long userId : followedIds) {
                    videoUserMap.get(userId).getUser().setFollowed(true);
                }
            }
        }
    }

    private Map<Long, UserPointInfo> getUserInfoFromMogon(List<Long> userIds) {
        if (userIds == null || userIds.size() == 0) {
            return new HashMap<Long, UserPointInfo>();
        }
        Object om = userFeignService.getUserInfoFromMongo(userIds).getBody().getData();
        ObjectMapper x = new ObjectMapper();
        List<UserPointInfo> userPointInfoList = x.convertValue(om, new TypeReference<List<UserPointInfo>>() {
        });
        return userPointInfoList.stream().collect(Collectors.toMap(UserPointInfo::getUserId, a -> a));
    }

    @Override
    public boolean deleteVideoById(Long id) {
        Video entity = new Video();
        entity.setId(id);
        entity.setDeleted(1);
        long nowSeconds = System.currentTimeMillis() / 1000;
        entity.setDeletedTime(nowSeconds);
        videoMapper.deleteRecommendIfExisted(id, nowSeconds);
        int result = videoMapper.updateByPrimaryKeySelective(entity);
        if (result <= 0) {
            return false;
        }

        //videoDao.deleteVideoById(id);
        // 同步solr
		/* 异步处理
		 * JSONObject obj = new JSONObject();
		obj.put("id", id);
		RocketMqUtil.send(MqTag.ROCKETMQ_BEAN_VIDEODELETETOSOLR, obj, MqTag.SEARCH);*/
        return true;
    }

    @Override
    public List<Long> getUpByVideoId(Long userId, List<Long> videoIds) {
        List<Long> list = videoUpMapper.findUserUpStateByUserIdAndVideoIds(userId, videoIds);
        return list;
    }

    @Override
    public void updateWaterMarkVideo(String waterMarkUrl, long id) {
        videoMapper.updateVideoWaterMarkVideoUrl(id, waterMarkUrl);
    }

    @Override
    public VideoWithWaterMarkInfo getVideoWithWatermarkById(Long id) {
        VideoWithWaterMarkInfo result = videoMapper.getVideoWithWatermarkById(id);
        ResponseEntity<Response> res = userFeignService.getVideoWaterMarkUserInfoById(result.getUserid());
        if (res.getStatusCodeValue() != 200) {
            throw new VideoException(StatusCode.USER_EXCEPTION);
        }
        if (res.getBody() == null) {
            throw new VideoException(StatusCode.USER_EXCEPTION);
        }
        if (res.getBody().getMeta().getCode() != 200) {
            throw new VideoException(StatusCode.USER_EXCEPTION);
        }
        Object o = res.getBody().getData();
        if (o == null) {
            throw new VideoException(StatusCode.USER_EXCEPTION);
        }
        ObjectMapper x = new ObjectMapper();
        UserInfo user = x.convertValue(o, UserInfo.class);
        result.setAccount(user.getAccount());
        result.setAvatar(user.getAvatar());
        return result;
    }

    @Override
    public Integer getCommentsCount(Long vid) {
        VideoComment record = new VideoComment();
        record.setVideoId(vid);
        record.setStatus(1);
        return videoCommentMapper.selectCount(record);
    }

    @Override
    public VideoInfo getVideoWithWatermarkById(long id) {
        return null;
    }

    @Override
    public boolean updateVideoWaterMarkUrl(Long videoId, String waterMarkUrl) {
        int result = videoMapper.updateVideoWaterMarkVideoUrl(videoId, waterMarkUrl);
        if (result <= 0) {
            throw new VideoException(StatusCode.VIDEO_EXCEPTION);
        }
        return true;
    }

    @Override
    public boolean updateVideoMusic(Long videoId, Long musicId) {
        int result = videoMapper.updateVideoMusic(videoId, musicId);
        if (result <= 0) {
            throw new VideoException(StatusCode.VIDEO_EXCEPTION);
        }
        return true;
    }

    @Override
    public JSONObject getHomepageVideoCount(Long userId) {
        List<Integer> list = videoMapper.getHomepageVideoCount(userId);
        // 获得某人视频的全部点赞数
        int upCount = videoMapper.getUpCountByUserId(userId);
        JSONObject obj = new JSONObject();
        obj.put("upVideoCount", list.size() > 0 ? list.get(0) : 0);
        obj.put("ownVideoCount", list.size() > 1 ? list.get(1) : 0);
        obj.put("upCount", upCount);
        return obj;
    }

    @Override
    public JSONObject sameMusicDetail(Long musicId) {
        // 音乐基本信息(封面、音乐、歌名、参与人数、是否收藏)
        Music muisc = musicMapper.selectByPrimaryKey(musicId);
        if (muisc == null || muisc.getDeleted() == 1) {
            throw new MusicException(StatusCode.MUSIC_EXCEPTION);
        }

        // 参与人数
        int usedMusicCount = videoMapper.getUsedMusicCount(musicId);

        // 判断是否收藏
        UserInfo user = GlobalController.getNowUser();
        boolean isCollect = false;
        String musicCollectKey = RedisKey.MUSIC_COLLECT_REDIS_KEY + user.getId();
        List collectList = rwRedisService.lrange(musicCollectKey, 0, -1);
        if (collectList != null && collectList.size() > 0) {
            for (Object object : collectList) {
                if (musicId.toString().equals(object.toString())) {
                    isCollect = true;
                    break;
                }
            }
        }

        // 构建接口返回信息
        JSONObject musicObj = new JSONObject();
        musicObj.put("music_id", musicId);
        musicObj.put("name", muisc.getType() == 0 ? muisc.getName() : null); // 0为系统，1为用户视频提取
        musicObj.put("music", muisc.getMusic());
        musicObj.put("cover", muisc.getCover());
        musicObj.put("type", muisc.getType());
        musicObj.put("owner_id", muisc.getUserId()); // 音乐创作者ID
        musicObj.put("owner_nickname", getOwnerNickname(muisc.getUserId()));
        musicObj.put("use_count", usedMusicCount); // 参与人数
        musicObj.put("isCollect", isCollect); // 是否收藏
        musicObj.put("duration", muisc.getDuration()); // 音乐时长
        return musicObj;
    }

    private String getOwnerNickname(Long userId) {
        // 先从缓存中取
        UserInfo userInfo = (UserInfo) rwRedisService.hget(RedisKey.USER_REDIS_KEY, userId);
        if (userInfo != null) {
            return userInfo.getNickname();
        }
        // 远程调用拿到用户的nickname
        ResponseEntity<Response> rs = userFeignService.getVideoUserInfoById(userId);
        // Map data = (Map)rs.getBody().getData();
        return (String) ((Map) rs.getBody().getData()).get("nickname");
    }

    @Override
    public List<VideoInfo> getVideoInSameMusic(Long musicId, Integer page, Integer size) {
        Music muisc = musicMapper.selectByPrimaryKey(musicId);
        if (muisc == null || muisc.getDeleted() == 1) {
            throw new MusicException(StatusCode.MUSIC_EXCEPTION);
        }
        Integer offset = (page - 1) * size;
        List<Video> videoList = videoMapper.getVideoByMusicId(musicId, offset, size);
        if (muisc.getType() == 1) { // 1为用户视频提取,需要把音乐首发视频放在第一位
            Long firstVideoId = muisc.getVideoId(); // 音乐首发视频ID
            Video firstVideo = null;
            for (Video video : videoList) {
                if (video.getId().equals(firstVideoId)) {
                    firstVideo = video;
                    videoList.remove(video);
                    break;
                }
            }
            if (firstVideo != null) {
                videoList.add(0, firstVideo);
            }
        }
        List<VideoInfo> videoInfoList = new ArrayList<>();
        buildVideos(videoInfoList, videoList);
        return videoInfoList;
    }

    @Override
    public boolean syncDataForAddWaterMark(Integer startId, Integer endId) {
        List<WaterMarkVideoInfo> videolist = videoMapper.listVideoByStartIdAndEndId(startId, endId);
        for (WaterMarkVideoInfo video : videolist) {
            Map<String, Object> videoMap = new HashMap<>();
            videoMap.put("video", video.getVideo());
            videoMap.put("title", video.getTitle());
            videoMap.put("width", video.getWidth());
            videoMap.put("account", video.getAccount());
            videoMap.put("id", video.getId());
            videoMap.put("userId", video.getUserId());
            if (video.getMusicId() != null) {
                videoMap.put("musicId", video.getMusicId());
            }
            RocketMqUtil.send(MqTag.ROCKETMQ_BEAN_VIDEOADDWATERMARK, videoMap, MqTag.FFMPEG);
        }
        return false;
    }



}
